package system.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;

import system.dao.page.HibernateFilter;
import system.dao.page.HibernateSort;


/**
 * Created by IntelliJ IDEA.
 * User: 
 * Date: 2009-2-23
 * Time: 12:03:31
 * To change this template use File | Settings | File Templates.
 */
@SuppressWarnings("unchecked")
public class HibernateGenericDao<T, PK extends Serializable> extends HibernateDaoSupport {

    protected final Log logger = LogFactory.getLog(this.getClass());

    protected final Class<T> entityClass;

    protected String className;

    @Autowired
    public void init(SessionFactory sessionFactory) {

        super.setSessionFactory(sessionFactory);

    }

    public HibernateGenericDao() {
        this.entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        className = entityClass.getSimpleName();
    }


    /**
     * 修改或删除该对象
     *
     * @param entity 对象
     * @throws Exception 错误
     */
    public void saveOrUpdate(T entity) throws Exception {
        Assert.notNull(entity);

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("updating {0} instance", className));

        }
        super.getHibernateTemplate().saveOrUpdate(entity);

    }

    /**
     * 保存该对�?返回保存数据
     *
     * @param entity 对象
     * @return T
     */
    public T save(T entity) {

        Assert.notNull(entity);

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("updating {0} instance", className));

        }

        T result = (T) super.getHibernateTemplate().merge(entity);

        if (logger.isDebugEnabled()) {

            logger.debug("update successful");

        }

        return result;
    }

    /**
     * 删除该对�?
     *
     * @param entity 对象
     */
    public void remove(T entity) {

        Assert.notNull(entity);

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("deleting {0} instance", className));

        }

        super.getHibernateTemplate().delete(entity);

        if (logger.isDebugEnabled()) {

            logger.info("remove successful");

        }
    }

    /**
     * 按主键删除数�?
     *
     * @param id PK
     */
    public void remove(final PK id) {

        Assert.notNull(id);

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("deleting {0} instance", className));

        }

        super.getHibernateTemplate().delete((this.get(id)));

        if (logger.isDebugEnabled()) {

            logger.debug("remove successful");

        }
    }

    /**
     * 按条件删�?
     *
     * @param sql sql语句
     * @param obj 对象
     */
    public void remove(String sql, Object obj) {

        Assert.notNull(obj);
        Assert.notNull(sql);

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("deleting {0} instance", className));

        }

        super.getHibernateTemplate().delete(sql, obj);

        if (logger.isDebugEnabled()) {

            logger.debug("remove successful");

        }
    }

    /**
     * 按主键加载数�?
     *
     * @param id 主键
     * @return T
     */
    public T get(final PK id) {

        Assert.notNull(id);

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("finding {0} instance with id: {1}", className, id));

        }

        return (T) super.getHibernateTemplate().get(this.entityClass, id);

    }

    /**
     * 查询 该对象是否存�?
     *
     * @param entity 对象
     * @return boolean
     */
    public boolean contains(T entity) {
        Assert.notNull(entity);

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("contains {0} instance", className));

        }
        return super.getHibernateTemplate().contains(entity);
    }

    /**
     * 批量删除数据
     *
     * @param entities 批量删除
     */
    public void deleteAll(Collection<T> entities) {
        Assert.notNull(entities);

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("deleteAll {0} instance", className));

        }
        super.getHibernateTemplate().deleteAll(entities);

        if (logger.isDebugEnabled()) {

            logger.debug("deleteAll successful");

        }

    }

    /**
     * 批量添加或更�?
     *
     * @param entities 对象集合
     */
    public void saveOrUpdateAll(Collection<T> entities) {

        Assert.notNull(entities);

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("saveOrUpdateAll {0} instance", className));

        }
        super.getHibernateTemplate().saveOrUpdateAll(entities);

        if (logger.isDebugEnabled()) {

            logger.debug("saveOrUpdateAll successful");

        }
    }

    /**
     * 加载�?��数据
     *
     * @return List<T>
     */
    public List<T> list() {

        return super.getHibernateTemplate().loadAll(getEntityClass());

    }

    /**
     * 自定义常用HQL语句
     *
     * @param queryName HQL
     * @return List<T>
     */
    public List<T> findByNamedQuery(String queryName) {

        return super.getHibernateTemplate().findByNamedQuery(queryName);

    }

    /**
     * 自定义常用HQL语句
     *
     * @param queryName HQL
     * @param value     参数
     * @return List<T>
     */
    public List<T> findByNamedQuery(String queryName, Object... value) {

        return super.getHibernateTemplate().findByNamedQuery(queryName, value);

    }

    /**
     * 根据属�?查找对象.
     *
     * @param propertyName        属�?�?
     * @param value               属�?�?
     * @param rowStartIdxAndCount 可�?的分页参�?第一个参数为起始的记�?第二个参数为返回的对象数�?
     *                            eg.
     *                            <code>
     *                            findByProperty("country","china");      //查找属�?值country为china的对象，返回�?��对象.
     *                            findByProperty("country","china",0,10); //查找属�?值country为china的对象，返回�?-10个符合的对象.
     *                            </code>
     * @return List<T>
     */
    public List<T> findByProperty(final String propertyName, final Object value, final int... rowStartIdxAndCount) {

        Assert.hasLength(propertyName);

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("finding {0} instance with property: {1} , value: {2}", className, propertyName, value));

        }

        final String queryString = MessageFormat.format("from {0} model where model.{1}= ?", className, propertyName);

        int rowStartIdx = 0;
        int rowCount = 0;

        if (rowStartIdxAndCount != null && rowStartIdxAndCount.length > 0) {

            rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);

            if (rowStartIdxAndCount.length > 1) {

                rowCount = Math.max(0, rowStartIdxAndCount[1]);

            }
        }

        return findPaged(queryString, rowStartIdx, rowCount, value);

    }

    /**
     * 根据属�?查找唯一对象
     *
     * @param propertyName 属�?�?
     * @param value        属�?�?
     * @return 唯一对象.如果不存在符合条件的结果,返回Null,如果有多个对象符合条�?抛出异常.
     */
    public T findUniqueByProperty(final String propertyName, final Object value) {

        return uniqueOfList(findByProperty(propertyName, value));

    }

    /**
     * 获取全部对象.
     *
     * @param rowStartIdxAndCount 可�?的分页参�?第一个参数为起始的记�?第二个参数为返回的对象数�?
     *                            eg.
     *                            <code>
     *                            findAll();     //返回�?��对象
     *                            findAll(0,10); //返回�?-10个对�?
     *                            </code>
     * @return List<T>
     */
    public List<T> findAll(final int... rowStartIdxAndCount) {

        if (logger.isDebugEnabled()) {

            logger.debug(MessageFormat.format("finding all {0} instances", className));

        }

        final String queryString = MessageFormat.format("from {0} model", className);

        int rowStartIdx = 0;
        int rowCount = 0;

        if (rowStartIdxAndCount != null && rowStartIdxAndCount.length > 0) {

            rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);

            if (rowStartIdxAndCount.length > 1) {

                rowCount = Math.max(0, rowStartIdxAndCount[1]);

            }

        }
        return findPaged(queryString, rowStartIdx, rowCount);

    }

    /**
     * 查询相关数据
     *
     * @param queryString HQL
     * @return 对象集合
     */
    public List<T> findByOrder(final String queryString) {

        Assert.hasLength(queryString);

        return super.getHibernateTemplate().find(queryString);

    }
    
    /**
     * 直接使用查询语句查询
     *
     * @param queryString 查询HQL语句
     * @param values      任意数量的参�?
     * @return List
     */
    public List<T> find(final String queryString, final Object... values) {
    	
    	Assert.hasLength(queryString);
    	
    	return super.getHibernateTemplate().find(queryString, values);
    	
    }

    /**
     * 直接使用查询语句查询结果，返回的列表中对象不�?��类型
     *
     * @param queryString 查询HQL语句
     * @param values      任意数量的参�?
     * @return List
     */
    public List<Object> findObject(final String queryString, final Object... values) {

        Assert.hasLength(queryString);

        return super.getHibernateTemplate().find(queryString, values);

    }

    /**
     * 按对象查�?
     *
     * @param o 对象
     * @return List
     */
    public List<T> findByObject(Object o) {

        Assert.isNull(o);

        return super.getHibernateTemplate().findByExample(o);

    }

    /**
     * 返回唯一的对�?
     *
     * @param queryString HQL
     * @param values      参数
     * @return Object
     */
    public Object findUnique(final String queryString, final Object... values) {

        Assert.hasLength(queryString);

        return uniqueOfList(super.getHibernateTemplate().find(queryString, values));

    }

    /**
     * 直接使用查询语句查询,带分页参�?
     *
     * @param queryString HQL语句
     * @param rowStartIdx 起始的记�?如不想设定，可设�?1.
     * @param rowCount    返回的记录数,如不想设定，可设�?1.
     * @param values      任意数量的参�?
     * @return List
     */
    public List<T> findPaged(final String queryString, final int rowStartIdx, final int rowCount, final Object... values) {

        return super.getHibernateTemplate().executeFind(new HibernateCallback() {

            public Object doInHibernate(Session session) throws HibernateException, SQLException {

                org.hibernate.Query query = session.createQuery(queryString);

                if (null != values) {

                    for (int i = 0; i < values.length; i++) {

                        query.setParameter(i, values[i]);

                    }

                }
                if (rowStartIdx > 0) {

                    query.setFirstResult(rowStartIdx);

                }
                if (rowCount > 0) {

                    query.setMaxResults(rowCount);

                }

                return query.list();

            }
        });
    }


    /**
     * 取得entity的class.
     *
     * @return Class<T>
     */
    public Class<T> getEntityClass() {

        return entityClass;

    }

    /**
     * 取出列表的第�?��对象.
     * 如果列表为空返回Null,如果有多于一个对�?抛出异常.
     *
     * @param list 对象的集�?
     * @param <E>  对象
     * @return 如果列表为空返回Null,如果有多于一个对�?抛出异常.
     */
    private static <E> E uniqueOfList(List<E> list) {

        if (list == null || list.isEmpty()) {

            return null;
        }

        if (list.size() > 1) {
            System.out.println("rows greate one!");
            return null;
        }
        
        return list.get(0);

    }

    /**
     * 查询返回的�?�?
     *
     * @param filter 条件
     * @return int
     */
    public int getEntitysCountWithFilter(final HibernateFilter filter) {
        Integer count = (Integer) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(entityClass);
                criteria = filter.execute(criteria);
                criteria.setProjection(Projections.rowCount());
                return criteria.uniqueResult();
            }
        });
        return count.intValue();
    }

    /**
     * 查询返回的结�?
     *
     * @param filter   条件
     * @param sort     排序
     * @param rowStart �?��
     * @param rowEnd   结束
     * @return List
     */
    public List<T> getEntitysWithFilterAndSort(final HibernateFilter filter, final HibernateSort sort, final int rowStart, final int rowEnd) {
        List applications = (List) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(entityClass);
                criteria = filter.execute(criteria);
                criteria = sort.execute(criteria);
                criteria.setFirstResult(rowStart);
                criteria.setMaxResults(rowEnd - rowStart);
                return criteria.list();
            }
        });

        return applications;
    }

     /**
     * 查询返回的结�?
     *
     * @param filter   条件
     * @param sort     排序
     * @return List
     */
    public List<T> getEntitysWithFilterAndSort(final HibernateFilter filter, final HibernateSort sort) {
        List applications = (List) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(entityClass);
                criteria = filter.execute(criteria);
                criteria = sort.execute(criteria);
                return criteria.list();
            }
        });

        return applications;
    }
}
